package cn.t.dynamic.switcher.aspect;

import cn.t.dynamic.switcher.annotation.Dynamic;
import cn.t.dynamic.switcher.router.DynamicDataSourceContextHolder;
import cn.t.dynamic.switcher.type.DataSourceType;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;

/**
 * 使用注解处理数据源切换的切面类
 */
@Aspect
@Order(-1) // 高优先级-必须要比@Transacation高
public class DynamicSwitchAspect {

    private static final Logger logger = LoggerFactory.getLogger(DynamicSwitchAspect.class);

    /**
     * 切点
     */
    @Pointcut("@annotation(cn.t.dynamic.switcher.annotation.Dynamic) || @within(cn.t.dynamic.switcher.annotation.Dynamic)")
    public void pointCut() {}

    /**
     * 方法执行前切换数据源
     * @param joinPoint 连接点信息
     */
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        // 此处注解信息一定存在于类上或者方法上
        // 优先使用方法上的注解
        Dynamic d = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(Dynamic.class);
        if (d == null) {
            d = joinPoint.getTarget().getClass().getAnnotation(Dynamic.class);
        }

        String target = d.target();
        DataSourceType type = d.type();

        if (target.isEmpty() && type.equals(DataSourceType.DEFAULT)) {
            // 使用默认的数据源
            DynamicDataSourceContextHolder.master();
        } else if (!target.isEmpty() && type.equals(DataSourceType.DEFAULT)) {
            // 指定数据源
            DynamicDataSourceContextHolder.specify(target);
        } else if (target.isEmpty() && type.equals(DataSourceType.SLAVE)) {
            // 随机选取从数据源
            DynamicDataSourceContextHolder.slave();
        } else if (!target.isEmpty() && type.equals(DataSourceType.SLAVE)) {
            // 指定从数据源
            DynamicDataSourceContextHolder.slave(target);
        } else {
            // 排除所有情况后
            // 主数据源
            DynamicDataSourceContextHolder.master();
        }
        logger.info("datasource conversion completed");
    }

    /**
     * 方法执行后清空切换key
     * @param joinPoint 连接点信息
     */
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        logger.info("datasource key will be reset...");
        DynamicDataSourceContextHolder.reset();
    }
}
